package cc.magicjson.example.demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.LongStream;

/**
 * 验证莫提霍尔问题
 * MontyHall问题简易描述:
 * 参赛者在三个门中选择一个，然后主持人（蒙提·霍尔）会揭示一个未被选中且后面没有奖品的门，
 * 接着询问参赛者是否要改变原来的选择以提高赢得隐藏在门后奖品的概率
 * <p>
 * 编程思路：
 * 1.准备对象:门后奖品、选择策略（保留选择、重选择）、命中次数
 * 2.步骤：
 * -2.1.准备门后奖品与选择策略
 * <p>
 * 使用Java 8 Stream API进行代码验证
 *
 * @author MagicJson <a href='mailto:it_magicjson@163.com'>MagicJson</a>
 * @since 1.0.0
 */
public class MontyHallProblem {
    public static void main(String[] args) {
        long totalTrials = 100000L;
        long stayWins = runExperiment(totalTrials, Strategy.STAY);
        long switchWins = runExperiment(totalTrials, Strategy.SWITCH);

        System.out.printf("坚持原选择赢得车的概率: %.2f%%\n", (double) stayWins / totalTrials * 100);
        System.out.printf("改变选择赢得车的概率: %.2f%%\n", (double) switchWins / totalTrials * 100);
    }

    private static long runExperiment(long trials, Strategy strategy) {
        return LongStream.range(0, trials)
                .mapToObj(trial -> simulateGame(strategy))
                .filter(prize -> prize == Prize.CAR)
                .count();
    }

    private static int revealAndRemoveGoat(List<Prize> doors, int initialChoiceIndex) {
        // 保存汽车所在的索引，用于后续计算新的初始选择索引
        int carIndex = -1;
        for (int i = 0; i < doors.size(); i++) {
            if (doors.get(i) == Prize.CAR) {
                carIndex = i;
                break;
            }
        }
        // 找到并移除一扇羊门
        for (int i = 0; i < doors.size(); ) {
            if (doors.get(i) == Prize.GOAT && i != initialChoiceIndex && i != carIndex) {
                doors.remove(i);
                break;
            } else {
                i++;
            }
        }
        // 计算新的初始选择索引（如果羊门被移除）
        if (initialChoiceIndex > doors.size() - 1 || initialChoiceIndex == carIndex) {
            // 如果初始选择已经被移除或与汽车重合，则重新选择一个有效的索引
            initialChoiceIndex = new Random().nextInt(doors.size());
        }
        return initialChoiceIndex;
    }

    private static Prize simulateGame(Strategy strategy) {
        List<Prize> doors = new ArrayList<>(Arrays.asList(Prize.CAR, Prize.GOAT, Prize.GOAT));
        int initialChoiceIndex = revealAndRemoveGoat(doors, new Random().nextInt(doors.size()));

        // 根据策略返回最终选择的门
        if (strategy == Strategy.STAY) {
            return doors.get(initialChoiceIndex);
        } else {
            int nextAvailableIndex = initialChoiceIndex + 1;
            if (nextAvailableIndex < doors.size()) {
                return doors.get(nextAvailableIndex);
            } else {
                // 如果只剩下一扇门，则返回这扇门
                return doors.get(0);
            }
        }
    }

    enum Prize {CAR, GOAT}

    enum Strategy {STAY, SWITCH}


}
